#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>

#define WIDTH 400
#define HEIGHT 300
#define NUM_SURFACES 4

typedef struct {
    Window win;
    GC gc;
    int width;
    int height;
} Surface;

Surface surfaces[NUM_SURFACES];
Display *dpy;
Window root_win;

void create_surface(Surface *s, int x, int y, int width, int height, const char *name) {
    XSetWindowAttributes attrs;
    attrs.background_pixel = BlackPixel(dpy, DefaultScreen(dpy));
    attrs.event_mask = ExposureMask | StructureNotifyMask;
    
    s->win = XCreateWindow(
        dpy, root_win,
        x, y, width, height, 0,
        CopyFromParent, InputOutput, CopyFromParent,
        CWBackPixel | CWEventMask, &attrs
    );
    
    // 设置窗口标题
    XStoreName(dpy, s->win, name);
    
    // 创建图形上下文
    XGCValues gcv;
    gcv.foreground = WhitePixel(dpy, DefaultScreen(dpy));
    gcv.graphics_exposures = 0;
    s->gc = XCreateGC(dpy, s->win, GCForeground | GCGraphicsExposures, &gcv);
    
    s->width = width;
    s->height = height;
    
    // 映射窗口
    XMapWindow(dpy, s->win);
}

void draw_surface(Surface *s) {
    // 随机颜色
    unsigned long color = random() & 0xFFFFFF;
    
    // 更改前景色
    XSetForeground(dpy, s->gc, color);
    
    // 绘制填充矩形
    XFillRectangle(dpy, s->win, s->gc, 0, 0, s->width, s->height);
    
    // 绘制一些文本
    const char *text = "X11 Surface";
    XDrawString(dpy, s->win, s->gc, 10, 20, text, strlen(text));
}

void init_composite() {
    // 检查复合扩展是否可用
    int event_base, error_base;
    if (!XCompositeQueryExtension(dpy, &event_base, &error_base)) {
        fprintf(stderr, "Composite extension not available\n");
        exit(1);
    }
    
    // 重定向所有窗口
    XCompositeRedirectSubwindows(dpy, root_win, CompositeRedirectManual);
}

void composite_surfaces() {
    // 创建一个父窗口用于合成
    XSetWindowAttributes attrs;
    attrs.background_pixel = BlackPixel(dpy, DefaultScreen(dpy));
    attrs.event_mask = ExposureMask | StructureNotifyMask;
    
    Window composite_win = XCreateWindow(
        dpy, root_win,
        100, 100, WIDTH + 50, HEIGHT + 50, 0,
        CopyFromParent, InputOutput, CopyFromParent,
        CWBackPixel | CWEventMask, &attrs
    );
    
    XStoreName(dpy, composite_win, "Composite Window");
    
    // 将各个surface作为子窗口附加到合成窗口
    for (int i = 0; i < NUM_SURFACES; i++) {
        XReparentWindow(
            dpy,
            surfaces[i].win,
            composite_win,
            10 + (i % 2) * (WIDTH / 2 + 10),
            10 + (i / 2) * (HEIGHT / 2 + 10)
        );
        
        // 调整大小
        XResizeWindow(dpy, surfaces[i].win, WIDTH / 2 - 5, HEIGHT / 2 - 5);
    }
    
    // 映射合成窗口
    XMapWindow(dpy, composite_win);
    XFlush(dpy);
}

int main() {
    // 初始化连接
    dpy = XOpenDisplay(NULL);
    if (!dpy) {
        fprintf(stderr, "Failed to open display\n");
        return 1;
    }
    
    root_win = DefaultRootWindow(dpy);
    
    // 初始化复合扩展
    init_composite();
    
    // 创建多个surface
    char name[32];
    for (int i = 0; i < NUM_SURFACES; i++) {
        snprintf(name, sizeof(name), "Surface %d", i+1);
        create_surface(&surfaces[i], 50 + (i % 2) * (WIDTH + 20), 50 + (i / 2) * (HEIGHT + 20), 
                      WIDTH, HEIGHT, name);
    }
    
    // 绘制各个surface
    for (int i = 0; i < NUM_SURFACES; i++) {
        draw_surface(&surfaces[i]);
    }
    XFlush(dpy);
    
    // 等待一会儿让窗口显示
    sleep(2);
    
    // 合成surface
    composite_surfaces();
    
    // 事件循环
    XEvent event;
    while (1) {
        XNextEvent(dpy, &event);
        switch (event.type) {
            case Expose:
                for (int i = 0; i < NUM_SURFACES; i++) {
                    if (event.xexpose.window == surfaces[i].win) {
                        draw_surface(&surfaces[i]);
                        XFlush(dpy);
                        break;
                    }
                }
                break;
            default:
                break;
        }
    }
    
    // 清理
    for (int i = 0; i < NUM_SURFACES; i++) {
        XDestroyWindow(dpy, surfaces[i].win);
        XFreeGC(dpy, surfaces[i].gc);
    }
    XCloseDisplay(dpy);
    
    return 0;
}
